/*
 * Time-based One-Time Password
 */

#include "user_password.h"

#if GKT_USER_PASSWORD_DYNAMIC_ENABLE \
	&& USER_DYNPWD_TOTP_ENABLE
/************************************************************
* BPK Key:A total of 32 uint32_t 
*		  uint32_t [0~8]:Refer to gkt_retmem.h
*
*		user dynpwd totp enable
*		  uint32_t [9]:totp_last_steps[password admin 0]
*		  uint32_t [10]:totp_last_steps[password admin 1]
*		  uint32_t [11]:totp_last_steps[password admin 2]
*		  uint32_t [12]:totp_last_steps[password admin 3]	
************************************************************/
static const gkt_date_time_s sc_dynpwd_totp_dt_base = 
	GKT_DATE_TIME(USER_DYNPWD_BASE_YEAR, 1, 1, 0, 0, 0);

int user_dynpwd_totp_verify(uint32_t *user_id, 
				const uint8_t *data)
{
	gkt_date_time_s dt;
	const user_password_item_s *c_item;
	uint8_t totp[USER_DYNPWD_TOTP_SIZE];
	uint32_t seconds_elapsed;
	uint32_t time_steps_start, time_steps_end, time_steps;
	uint32_t totp_last_steps;
	uint32_t i, j, admin_nums, item_index;
	int retval;

	retval = gkt_rtc_get_time(&dt);
	if (GKT_SUCCESS == retval) {
		retval = gkt_dt_seconds_elapsed_from_base(&dt, 
					&sc_dynpwd_totp_dt_base, &seconds_elapsed);
		if (GKT_SUCCESS == retval) {
			if (seconds_elapsed >= USER_DYNPWD_TOTP_TIME_STEP_S)
				time_steps_start = (seconds_elapsed - USER_DYNPWD_TOTP_TIME_STEP_S) 
									/ USER_DYNPWD_TOTP_TIME_STEP_S;
			else
				time_steps_start = seconds_elapsed / USER_DYNPWD_TOTP_TIME_STEP_S;
			time_steps_end = (seconds_elapsed + USER_DYNPWD_TOTP_TIME_STEP_S - 1) 
								/ USER_DYNPWD_TOTP_TIME_STEP_S;
			gkt_trace("password_totp: time_step - %u ~ %u\n", 
						time_steps_start, time_steps_end);

			admin_nums = g_user_password_info.auth_user_used_nums[GKT_USER_AUTH_ADMIN];
			for (i = 0; i < admin_nums; i++) {
				totp_last_steps = g_user_dynpwd_info.totp_last_steps[i];
				if (totp_last_steps > 0) {
					time_steps = gkt_max(totp_last_steps + 1, time_steps_start);
					if (time_steps_end < time_steps)
						continue;
				}
				else
					time_steps = time_steps_start;
				
				item_index = g_user_dynpwd_info.admin_item_indexs[i];
				if (item_index < g_user_password.instance.item_available_nums) {
					c_item = USER_PASSWORD_ITEM_C(item_index);
					do {
						retval = gkt_totp_generate(time_steps,
								c_item->data, c_item->data_length,
								(char *)totp, USER_DYNPWD_TOTP_SIZE);
						if (GKT_SUCCESS == retval) {	
							for (j = 0; j < USER_DYNPWD_TOTP_SIZE; j++) {
								if (totp[j] != data[j])
									break;
							}

							if (USER_DYNPWD_TOTP_SIZE == j) {	/* matched */
								g_user_dynpwd_info.totp_last_steps[i] = time_steps;
								G_BPK_WriteKey(&g_user_dynpwd_info.totp_last_steps[i], 1, i + GKT_RETMEM_USER_DYNPWD_ADMIN0_PWD);
								
								*user_id = GKT_USER_ID_BUILD_FULL(GKT_USER_AUTH_TEMPORARY, 0,
												GKT_USER_TYPE_PASSWORD,
												GKT_USER_PASSWORD_TOTP,
												c_item->header.user_index);
								gkt_trace("password_totp: PASSED - %u\n", 
										c_item->header.user_index);
								return GKT_USER_VERIFY_PASSED;
							}
						}

						time_steps++;
					} while (time_steps <= time_steps_end);
				}
			}
		}
	}

	return GKT_USER_VERIFY_FAILED;
}

#endif

